<?php
/**
 * Шаблон постраничного вывода
 *
 * Помогает в определении общего числа элементов и количества страниц, на которых они должны выводиться
 *
 * @author Дмитрий Кузьма <kouzma.d@gmail.com>
 * @version 1.0
 */

class Service_ArrayConverter {
  /**
   * Конвертирует обычный двумерный массив в дерево согласно ссылкам данного массива
   *
   * @param array $arrIn - двумерный массив
   * @param string $idName - название идентификатора, например 'ID_in'
   * @param string $rootName - название указателя на корневой элемент, например 'root_in'
   * @return array
   */
  /*public static function convertToTreeArray($arrIn, $idName, $rootName) {
    $arrOut = array();
    $arrSize = sizeof($arrIn);
    $linkArray = array();
    for ($i = 0; $i < $arrSize; $i++) {
    	$id = $arrIn[$i][$idName];
      $root = $arrIn[$i][$rootName];

      if ($root == null) {
        $arrOut[] = $arrIn[$i];
        $linkArray[$id] = &$arrOut[(sizeof($arrOut) -1)];
      }
      else{
        $linkArray[$root]['children'][] = $arrIn[$i];
        $linkArray[$id]= &$linkArray[$root]['children'][(sizeof($linkArray[$root]['children']) -1)];
      }
    }
    return $arrOut;
  }  */

  /**
   * Конвертирует обычный двумерный массив в дерево согласно ссылкам данного массива
   *
   * @param array $arrIn - двумерный массив
   * @param string $idName - название идентификатора, например 'ID_in'
   * @param string $rootName - название указателя на корневой элемент, например 'root_in'
   * @return array
   */
  public static function convertToTreeArray($arrIn, $idName, $rootName) {
    $arrOut = array();
    $linkArray = array();
    do {
    	$changed = false;
    	$arrSize = sizeof($arrIn);
  	  $unsortArray = array();
	    for ($i = 0; $i < $arrSize; $i++) {
	    	$id = $arrIn[$i][$idName];
	      $root = $arrIn[$i][$rootName];

	      if ($root == null) {
	        $arrOut[] = $arrIn[$i];
	        $linkArray[$id] = &$arrOut[(sizeof($arrOut) -1)];
	        $changed = true;
	      }
	      else{
	        if (isset($linkArray[$root])) {
	        	$linkArray[$root]['children'][] = $arrIn[$i];
	          $linkArray[$id]= &$linkArray[$root]['children'][(sizeof($linkArray[$root]['children']) -1)];
	          $changed = true;
	        }
	        else
	          $unsortArray[] = $arrIn[$i];
	      }
	    }
	    $arrIn = $unsortArray;
    } while(sizeof($unsortArray) && $changed);
    return $arrOut;
  }

  /**
   * Функция сортирует элементы древовидного массива согласно заданному полю
   *
   * @param array $arrIn - древовидный массив
   * @param string $sortFieldName - поле, по которому следует сортировать
   * @return array - отсортированный массив
   */
  public static function sortTreeArray($arrIn, $sortFieldName) {
    $tempSize = sizeof($arrIn);
    for ($i = 0; $i < $tempSize; $i++) // сортируем вложенные массивы
    	if ( isset($arrIn[$i]['children']) )
    	  $arrIn[$i]['children'] = self::sortTreeArray($arrIn[$i]['children'], $sortFieldName);
    for ($i = 0; $i < $tempSize; $i++) // сортируем основной массив
      for ($j = $i; $j < $tempSize; $j++)
    		if ($arrIn[$j][$sortFieldName] < $arrIn[$i][$sortFieldName]) {
    			 $temp = $arrIn[$i];
    		  $arrIn[$i] = $arrIn[$j];
    		  $arrIn[$j] = $temp;
    		}
    return $arrIn;
  }

    /**
   * Функция сортирует элементы древовидного массива согласно заданному полю
   *
   * @param array $arrIn - древовидный массив
   * @param string $sortFieldName - поле, по которому следует сортировать
   * @return array - отсортированный массив
   */
  public static function sortTreeArrayForAlbum($arrIn, $sortFieldName) {
    $tempSize = sizeof($arrIn);
    for ($i = 0; $i < $tempSize; $i++) // сортируем основной массив
      for ($j = $i; $j < $tempSize; $j++)
    		if ($arrIn[$j][$sortFieldName] < $arrIn[$i][$sortFieldName]) {
    		  $temp = $arrIn[$i];
    		  $arrIn[$i] = $arrIn[$j];
    		  $arrIn[$j] = $temp;
    		}
    return $arrIn;
  }

  /**
   * Метод вычленяет колонку из двумерного массива
   *
   * @param array $arrIn - двумерный массив
   * @param mixed $columnName - название или номер колонки, которую нужно вернуть
   * @return array - одномерный массив, соответствующий колонке входного
   */
  public static function getColumn($arrIn, $columnName) {
    $arrOut = array();
    $arrSize = sizeof($arrIn);
    for ($i = 0; $i < $arrSize; $i++)
    	$arrOut[$i] = $arrIn[$i][$columnName];
    return $arrOut;
  }

  /**
   * Метод вычленяет колонку из двумерного массива и возвращает ее в строковом виде через разделитель
   *
   * @param array $arrIn - двумерный массив
   * @param mixed $columnName - название или номер колонки, которую нужно вернуть
   * @param mixed $glue - разделитель для возвращаемой строки
   * @return string - строка, соответствующая колнке входно массива
   */
  public static function getColumnAsString($arrIn, $columnName, $glue = ', ') {
    $strOut = '';
    $arrSize = sizeof($arrIn);
    if (!$arrSize) return null;
    for ($i = 0; $i < $arrSize; $i++) {
      if ($i) $strOut .= $glue;
      $strOut .= $arrIn[$i][$columnName];
    }
    return $strOut;
  }
  /**
   * Метод аналогичен методу implode, но обрабатывает одну колонку массива
   *
   * @param string $glue - разделитель
   * @param array $arrIn - двумерный массив
   * @param mixed $columnName - название или номер колонки, которую нужно вернуть
   * @return array - одномерный массив, соответствующий колонке входного
   */
  public static function implodeColumn($glue, $arrIn, $columnName) {
    $strOut = '';
    $arrSize = sizeof($arrIn);
    if (!$arrSize)
      return $strOut;
    for ($i = 0; $i < $arrSize; $i++)
    	$strOut .= $arrIn[$i][$columnName] . $glue;
    return substr($strOut, 0, -strlen($glue));
  }
  /*
  public static function addSubArray(&$mainArray, string $idName, &$subArray, string $rootName = 'root', string $subArrayNewName = 'children') {
    $subArraySize = sizeof($subArray);
    $tempArray = array();
    for ($i = 0; $i < $subArraySize; $i++) {
      $tempArray[ $arrQuestionsTags[$i]['ID_essence'] ][]
    }


    $arrSize = sizeof($arrIn);
    $linkArray = array();
    for ($i = 0; $i < $arrSize; $i++) {
      $id = $arrIn[$i][$idName];
      $root = $arrIn[$i][$rootName];

      if ($root == null) {
        $arrOut[] = $arrIn[$i];
        $linkArray[$id] = &$arrOut[(sizeof($arrOut) -1)];
      }
      else{
        $linkArray[$root]['children'][] = $arrIn[$i];
        $linkArray[$id]= &$linkArray[$root]['children'][(sizeof($linkArray[$root]['children']) -1)];
      }
    }
  }*/

	  /**
	 * Из двух массивов формируем новый, содержащий элементы первого массива, которых нет во втором массиве
	 *
	 * @param array $arr1
	 * @param array $arr2
	 * @param boolean $strictLowerCase - строго, с понижением регистра
	 * @return array
	 */
	public static function arrayFullDifference($arr1, $arr2, $strictLowerCase = false, $specialchars = 0) {
	  if (empty($arr2))
	    return $arr1;
		if ($specialchars == 2)
		  $arr2 = array_map('htmlspecialchars', $arr2);
	  $arrNotExists = array();
	  if ($arr1) foreach ($arr1 as $arr1Element) {
	    $isArr1ElemInArr2 = false;
	    if ($strictLowerCase) {
	      if (!self::in_iarray(($specialchars ==1) ? htmlspecialchars($arr1Element) : $arr1Element, $arr2))
	        $arrNotExists[] = $arr1Element;
	    }
	    else {
	      if (!in_array(($specialchars ==1) ? htmlspecialchars($arr1Element) : $arr1Element, $arr2))
	        $arrNotExists[] = $arr1Element;
	    }
	  }
	  return $arrNotExists;
	}

  /**
   * Метод проверяет элемент на вхождение в массив (без учета возмоэжной многомерности)
   *
   * @param mixed $val
   * @param array $arr
   * @return bool
   */
	public static function in_iarray($val, $arr) {
	  $arrSize = sizeof($arr);
	  for ($i = 0; $i < $arrSize; $i++)
	    if (Service_Function::strtolowerU($val) == Service_Function::strtolowerU($arr[$i]))
	      return true;
	  return false;
	}
	/**
	 * Метод возвращает массив, идентичный переданному, но содержащий только уникальные в рамках массива элементы
	 *
	 * @param array $arr
	 * @return array
	 */
	public static function array_iunique($arr) {
	  $n = array();
	  $arrSize = sizeof($arr);
	  for ($i = 0; $i < $arrSize; $i++)
	    if (!self::in_iarray($arr[$i], $n))
	      $n[] = $arr[$i];
	  return $n;
	}

	/**
	 * Метод делает из многоуровнего массива, массив основанный на ключах со второго уровня
	 *
	 * @param array $arrIn
	 * @param int $key
	 * @return array
	 */
	public static function makeKeyArrayFromMultyArray($arrIn, $key) {
		$retArray = array();
		for ($i = 0; $i < sizeof($arrIn); $i++) {
		  $retArray[$arrIn[$i][$key]] = $arrIn[$i];
		}
		return $retArray;

	}



	/**
	 * Из двух ассоциативных массивов формируем новый, содержащий элементы первого массива, которых нет во втором массиве
	 *
	 * @param array $arr1
	 * @param array $arr2
	 * @param string $strField1 - поле первого ассоциативного массива, по которому производится сравнение
	 * @param string $strField2 - поле второго ассоциативного массива, по которому производится сравнение
	 * @return array
	 */
	public static function getDataArraysFullDiff($arr1, $arr2, $strField1, $strField2) {
	  $arrNotExists = array();
	  foreach ($arr1 as $arr1Element) {
	    $isArr1ElemInArr2 = false;
	    foreach ($arr2 as $arr2Element) {
	      if ($arr1Element[$strField1] == $arr2Element[$strField2]) {
	        $isArr1ElemInArr2 = true;
	        break;
	      }
	    }
	    if (!$isArr1ElemInArr2)
	      $arrNotExists[] = $arr1Element;
	  }
	  return $arrNotExists;
	}

	/**
	 * Возвращаем колонку из двумерного ассоциативного массива
	 *
	 * @param array $arrSrc
	 * @param string $strField
	 * @return array
	 */
	public static function getArrayColumn($arrSrc, $strField) {
	  $arrColumn = array();
	  foreach ($arrSrc as $arrElement)
	    $arrColumn[] = $arrElement[$strField];
	  return $arrColumn;
	}

/**
	 * Формирует простой массив из сложного
	 *
	 * @param array $arr
	 * @param string $fieldName
	 * @return array
	 */
  public static function getSimpleArray($arr, $fieldName) {
		$arrSimple = array();
		if ($arr) foreach ($arr as $element) {
			$arrSimple[] = $element[$fieldName];
		}
		return $arrSimple;
  }



  /**
   * Получаем среднее значение массива
   *
   * @param array of float|int $arr
   * @param string $fieldName - поле для извлечения (ассоциативный случай);
   * @return float
   */
  public static function getArrayAverageValue($arr, $fieldName = null) {
		if (!sizeof($arr)) return null;
    if ($fieldName) $arr = Service_ArrayConverter::getArrayColumn($arr, $fieldName);
		return array_sum($arr) / sizeof($arr);
  }

//
//  //Получаем списки всех вложенных разделов (модуль Типовые страницы)
//  public static function getChildrenIDsByTreeArray($lookInID, $foundBranch = false, $treeArray) {
//    $arrIDsToReturn = array();
//    foreach ($treeArray as $arrItem) {
//      if (!$foundBranch) {
//        if ($arrItem['ID_typical_page'] == $lookInID) {
//          return array_merge($arrIDsToReturn, self::getChildrenIDsByTreeArray(NULL, true, array($arrItem)));
//        }
//        else continue;
//      }
//      $arrIDsToReturn[] = $arrItem['ID_typical_page'];
//      if (isset($arrItem['children']))
//        $arrIDsToReturn = array_merge($arrIDsToReturn, self::getChildrenIDsByTreeArray(NULL, true, $arrItem['children']));
//    }
//    return $arrIDsToReturn;
//  }
//
//
//
  /**
   * Метод соединяет 2 массива хитрым образом
   * Первый массив (большой) имеет поле $strLinkColumn
   * Второй массив (малый) присоединяется к первом по связи с этим полем, формируя колонку $strCombineColumn
   *
   * @param array $bigArray
   * @param array $smallArray
   * @param string $strLinkColumn
   * @param string $strCombineColumn
   */
  public static function combineArrays($bigArray, $smallArray, $strLinkColumn, $strCombineColumn) {
  	$bigArraySize = sizeof($bigArray);
  	$smallArraySize = sizeof($smallArray);
		for ($j = 0; $j < $bigArraySize; $j++) {
			for ($i = 0; $i < $smallArraySize; $i++) {
				if (isset($smallArray[$i][$strLinkColumn]) && $smallArray[$i][$strLinkColumn] == $bigArray[$j][$strLinkColumn]) {
			    $bigArray[$j][$strCombineColumn][] = $smallArray[$i];
				}
			}
		}
		return $bigArray;
  }
  /**
   * Метод соединяет 2 массива хитрым образом
   * Первый массив (большой) имеет поле $strLinkColumn
   * Второй массив (малый) присоединяется к первом по связи с этим полем, формируя колонку $strCombineColumn
   *
   * @param array $bigArray
   * @param array $smallArray
   * @param string $strLinkColumn
   * @param string $strCombineColumn
   */
  public static function combineArraysAddOneField($bigArray, $smallArray, $strLinkFrom, $strLinkTo, $strCombineColumn, $strFieldFrom) {
  	$bigArraySize = sizeof($bigArray);
  	$smallArraySize = sizeof($smallArray);
		for ($j = 0; $j < $bigArraySize; $j++) {
			for ($i = 0; $i < $smallArraySize; $i++) {
				if (isset($smallArray[$i][$strLinkFrom]) && $smallArray[$i][$strLinkFrom] == $bigArray[$j][$strLinkTo]) {
			    $bigArray[$j][$strCombineColumn] = $smallArray[$i][$strFieldFrom];
			    break;
				}
			}
		}
		return $bigArray;
  }
  /**
   * Метод соединяет 2 массива хитрым образом
   * Первый массив (большой) имеет поле $idName (предположительно названи ID в БД)
   * Второй массив на первом уровне имеет числовые индексы. Он присоединяется соединяя числовой индекс с ID большого массива
   * Присоединение записывается в новое поле большого массива $strCombineColumn
   *
   * @param array $bigArray
   * @param array $smallArray
   * @param string $idName
   * @param string $strCombineColumn
   */
  public static function addIdsArray($bigArray, $smallArray, $idName, $strCombineColumn) {
  	$bigArraySize = sizeof($bigArray);
  	$smallArraySize = sizeof($smallArray);
		for ($i = 0; $i < $bigArraySize; $i++) {
		  $curId = $bigArray[$i][$idName];
			foreach ($smallArray as $smallKey => $smallElement) {
				if ($smallKey == $curId) {
					$bigArray[$i][$strCombineColumn] = $smallElement;
					break;
				}
			}
		}
		return $bigArray;
  }
  /**
   * Метд преобразовывает массив с ключами к обычному (если ключей нет во внутренней структуре массива, то они пропадут)
   *
   * @param array $arrKey
   * @return array
   */
  public static function makeUsualArrayFromKeyArray($arrKey) {
  	$retArr = array();
  	foreach ($arrKey as $record) {
  		$retArr[] = $record;
  	}
  	return $retArr;
  }

  /**
   * Метод производит сортировку по нескольким полям массива
   *
   * @param array $arrToSort
   * @param array $arrColumns - ассоциативный массив полей для сортировки, ключом является поле, а значением - направление
   * @return array
   */
  public static function sortMultyColumns($arrToSort, $arrColumns) {
		$retArr = $arrToSort;
  	for($i = 0; $i < sizeof($retArr); $i++) {
  		for ($j = $i; $j < sizeof($retArr); $j++) {
  			foreach ($arrColumns as $sortColumn => $sortType) {
				  if ($retArr[$i][$sortColumn] > $retArr[$j][$sortColumn] && $sortType == 'desc')
				    break;
  				elseif ($retArr[$i][$sortColumn] < $retArr[$j][$sortColumn] && $sortType == 'asc')
				    break;
				  elseif ($retArr[$i][$sortColumn] != $retArr[$j][$sortColumn]) {
				  	$temp = $retArr[$i];
				  	$retArr[$i] = $retArr[$j];
				  	$retArr[$j] = $temp;
				  	break;
				  }
  			}
  		}
  	}
  	return $retArr;
  }
  /**
   * Метод объединяет и сортирует переданные массивы по полю 'sort_num'
   *
   * @param array $arrInputs - массивы для объединения и сортировки в формате: array(0=>array1(0=>'', 1=>'', 2=>'', ...), 1=>array2(0=>'', 1=>'', 2=>'', ...), 2=>array3(0=>'', 1=>'', 2=>'', ...) ...)
   */
  public static function mergeAndSortArrays($arrInputs) {
  	$arrResult = array();
  	$size = sizeof($arrInputs); // сколько массивов надо объединить
  	for ($i=0; $i<$size; $i++) {
  		$arrInSize = sizeof($arrInputs[$i]);
  		for ($j=0; $j<$arrInSize; $j++) {
  			$arrResult[] = $arrInputs[$i][$j];
  		}
  	}
  	return self::sortTreeArray($arrResult, 'sort_num'); // сортровка блоков по возрастанию
  }

  /**
   * Метод создает новый массив из исходного преобразуя названия полей
   *
   * @param array $arrStart
   * @param array $arrFieldToCopy
   * @return array
   */
  public static function createArrayWithNewFields($arrStart, $arrFieldToCopy) {
  	$retArray = array();
  	if ($arrFieldToCopy && $arrStart) {
  		$i = 0;
  		foreach ($arrStart as $element) {
  			foreach ($arrFieldToCopy as $keyTo => $keyFrom) {
  				if (isset($element[$keyFrom]))
  				  $retArray[$i][$keyTo] = $element[$keyFrom];
  				else
  					$retArray[$i][$keyTo] = null;
  			}
  			if (isset($element['children']))
  			  $retArray[$i]['children'] = self::createArrayWithNewFields($element['children'], $arrFieldToCopy);
  			$i++;
  		}
  		return $retArray;
  	}
  	else return null;

  }
  /**
   * изменяет поля в основном массиве полями из второго, если равны поля с ключом $conditionField
   *
   * @param array $arrInput
   * @param array $arrUpdatedFields
   * @param string $conditionField
   * @return array
   */
  public static function updateFieldsInAssocArrayWithConditions($arrInput, $arrUpdatedFields, $conditionField) {
  	$sizeUpdatedFields = sizeof($arrUpdatedFields);
  	$sizeBaseArray = sizeof($arrInput);
  	for ($j=0; $j<$sizeUpdatedFields; $j++)
  		for ($i=0; $i<$sizeBaseArray; $i++)
  		//print_r($arrInput[$i]);
  			if ($arrUpdatedFields[$j][$conditionField] == $arrInput[$i][$conditionField])
  				$arrInput[$i] = $arrUpdatedFields[$j];

  	return $arrInput;
  }

  /**
   * Метод проверяет, находится ли некоторый элемент в массиве
   *
   * @param array $arr
   * @param mixed $value
   * @return bool
   */
  public static function isInArray($arr, $value) {
  	for ($i = 0; $i < sizeof($arr); $i++) {
  	  if ($arr[$i] == $value)
  	    return true;
  	}
  	return false;
  }

  /**
   * Удаляем все пустые элементы массив (сбрасываем при этом индексы)
   *
   * @param array $arr
   * @return array
   */
  public static function removeEmptyElements($arr) {
    if (empty($arr)) return array();
    foreach ($arr as $key => $value) {
      if (empty($value)) {
        unset($arr[$key]);
      }
    }
    return array_values($arr);
  }
  /**
   * Заменяем ключи в массиве
   *
   * @param array $arr - Исходный массив
   * @param array $arrOldKeys - список старых ключей к замене
   * @param array $arrNewKeys - список новык ключей (соответственно)
   * @return array
   */
  public static function renameKeys($arr, $arrOldKeys, $arrNewKeys) {
    if (empty($arr)) return array();
    $arrNew = array();
    foreach ($arr as $key => $subArr) {
      $arrEl = array();
      for ($j = 0; $j < sizeof($arrOldKeys); $j++) {
        $arrEl[$arrNewKeys[$j]] = $subArr[$arrOldKeys[$j]];
      }
      $arrNew[] = $arrEl;
    }
    return $arrNew;
  }

  /**
   * Удаляет ключи из массива
   *
   * @param $array - исходный массив
   * @param $arrKeys - массив с ключами
   * @return массив
   */
  public static function deleteFromArray($array, $arrKeys) {
  	foreach ($arrKeys as $key) {
  		if (isset($array[$key])) unset($array[$key]);
  	}
  	return $array;
  }





  /**
   * Метод возвращает часть массива с максимальным значением некоторого поля
   *
   * @param array $arrIn
   * @param string $fieldName
   * @param integer $amount
   * @return array
   */
  public static function getPartWithMaxFieldAmount($arrIn, $fieldName, $amount) {
    if (!$arrIn) return array();
    $arrTemp = self::sortMultyColumns($arrIn, array($fieldName => 'desc'));
    $arrOut = array();
    foreach ($arrTemp as $element) {
    	$arrOut[] = $element;
    	$amount--;
    	if (!$amount) break;
    }
    return $arrOut;
  }

}
?>